using Microsoft.EntityFrameworkCore;
using RAG.Application.Interfaces;
using RAG.Application.Dtos;
using RAG.Domain.Entities.App;
using RAG.Infrastructure.Data;
using System.Text;
using Microsoft.Extensions.Configuration;
using RAG.Application.Commands; // This using statement is crucial for ApiResult
using RAG.Application.Services; // For PermissionCheckService
using Microsoft.Extensions.DependencyInjection;

namespace RAG.Application.Services;

/// <summary>
/// 文档服务实现
/// </summary>
public class AppDocumentService : IAppDocumentService
{
    private readonly RagDbContext _db;
    private readonly IAppRagService _ragService;
    private readonly PermissionCheckService _permissionCheckService;
    private readonly IServiceScopeFactory _scopeFactory;

    public AppDocumentService(RagDbContext db, IAppRagService ragService, PermissionCheckService permissionCheckService, IServiceScopeFactory scopeFactory)
    {
        _db = db;
        _ragService = ragService;
        _permissionCheckService = permissionCheckService;
        _scopeFactory = scopeFactory;
    }

    /// <summary>
    /// 上传文档
    /// </summary>
    public async Task<ApiResult> UploadDocumentAsync(UploadDocumentDto dto)
    {
        try
        {
            // 验证知识库是否存在（所有用户都可以访问所有知识库）
            var knowledgeBase = await _db.KnowledgeBases
                .FirstOrDefaultAsync(kb => kb.KnowledgeBaseId == dto.KnowledgeBaseId && kb.IsActive && !kb.IsDeleted);
            
            if (knowledgeBase == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "知识库不存在");
            }

            // 生成文件路径
            var fileName = $"{Guid.NewGuid()}_{dto.File.FileName}";
            var filePath = Path.Combine("uploads", "documents", fileName);
            var fullPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", filePath);

            // 确保目录存在
            Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);

            // 保存文件
            using (var stream = new FileStream(fullPath, FileMode.Create))
            {
                await dto.File.CopyToAsync(stream);
            }

            // 创建文档实体
            var document = new Document
            {
                DocumentId = Guid.NewGuid(),
                UserId = dto.UserId,
                KnowledgeBaseId = dto.KnowledgeBaseId,
                DocumentTitle = dto.DocumentTitle,
                DocumentFileName = dto.File.FileName,
                DocumentFilePath = filePath,
                DocumentFileType = Path.GetExtension(dto.File.FileName).ToLower(),
                DocumentFileSize = dto.File.Length,
                DocumentStatus = "uploaded",
                DocumentAccessLevel = dto.DocumentAccessLevel,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            _db.Documents.Add(document);
            await _db.SaveChangesAsync();

            // 异步处理文档（分块和向量化） - 使用新的作用域，避免请求作用域释放
            _ = Task.Run(async () =>
            {
                try
                {
                    using var scope = _scopeFactory.CreateScope();
                    var scopedRagService = scope.ServiceProvider.GetRequiredService<IAppRagService>();
                    await scopedRagService.ProcessDocumentAsync(document.DocumentId);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"文档处理失败 {document.DocumentFileName}: {ex.Message}");
                }
            });

            return ApiResult.Success("文档上传成功", new { documentId = document.DocumentId });
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"上传文档失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 获取文档列表
    /// </summary>
    public async Task<ApiResult> GetDocumentsAsync(Guid userId, Guid? knowledgeBaseId = null)
    {
        try
        {
            // 检查用户是否具有查看所有文档的权限
            var canViewAll = await _permissionCheckService.CanViewAllAsync(userId, "document");
            
            var query = _db.Documents
                .Include(d => d.KnowledgeBase)
                .Include(d => d.User) // 包含用户信息以便显示创建者
                .AsQueryable();

            // 如果具有查看所有文档的权限，可以看到所有文档；否则只能看到自己的文档
            if (!canViewAll)
            {
                query = query.Where(d => d.UserId == userId && !d.IsDeleted);
            }
            else
            {
                query = query.Where(d => !d.IsDeleted);
            }

            if (knowledgeBaseId.HasValue)
            {
                query = query.Where(d => d.KnowledgeBaseId == knowledgeBaseId.Value);
            }

            var documents = await query
                .OrderBy(d => d.DocumentTitle).ThenBy(d => d.DocumentId) // 使用稳定的排序方式，避免启用禁用后上下跳动
                .Select(d => new
                {
                    d.DocumentId,
                    d.DocumentTitle,
                    d.DocumentFileName,
                    d.DocumentFileType,
                    d.DocumentFileSize,
                    d.DocumentStatus,
                    d.DocumentAccessLevel,
                    d.CreatedAt,
                    KnowledgeBaseName = d.KnowledgeBase.KnowledgeBaseName,
                    CreatorName = d.User.Username, // 显示创建者用户名
                    IsOwner = d.UserId == userId // 标识是否是当前用户的文档
                })
                .ToListAsync();

            return ApiResult.Success("获取文档列表成功", documents);
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"获取文档列表失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 获取文档详情
    /// </summary>
    public async Task<ApiResult> GetDocumentAsync(Guid documentId)
    {
        try
        {
            var document = await _db.Documents
                .Include(d => d.KnowledgeBase)
                .Include(d => d.DocumentChunks)
                .FirstOrDefaultAsync(d => d.DocumentId == documentId && !d.IsDeleted);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在");
            }

            var result = new
            {
                document.DocumentId,
                document.DocumentTitle,
                document.DocumentFileName,
                document.DocumentFileType,
                document.DocumentFileSize,
                document.DocumentStatus,
                document.DocumentAccessLevel,
                document.CreatedAt,
                KnowledgeBaseName = document.KnowledgeBase.KnowledgeBaseName,
                ChunkCount = document.DocumentChunks.Count
            };

            return ApiResult.Success("获取文档详情成功", result);
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"获取文档详情失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 删除文档（软删除）
    /// </summary>
    public async Task<ApiResult> DeleteDocumentAsync(Guid documentId, Guid userId)
    {
        try
        {
            var document = await _db.Documents
                .FirstOrDefaultAsync(d => d.DocumentId == documentId && d.UserId == userId && !d.IsDeleted);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在或无权限删除");
            }

            // 软删除文档
            document.IsDeleted = true;
            document.UpdatedAt = DateTime.UtcNow;

            // 软删除相关的文档块
            var documentChunks = await _db.DocumentChunks
                .Where(dc => dc.DocumentId == documentId)
                .ToListAsync();

            foreach (var chunk in documentChunks)
            {
                chunk.IsDeleted = true;
                chunk.UpdatedAt = DateTime.UtcNow;
            }

            await _db.SaveChangesAsync();

            return ApiResult.Success("文档删除成功");
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"删除文档失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 更新文档
    /// </summary>
    public async Task<ApiResult> UpdateDocumentAsync(UpdateDocumentDto dto)
    {
        try
        {
            var document = await _db.Documents
                .FirstOrDefaultAsync(d => d.DocumentId == dto.DocumentId && d.UserId == dto.UserId && !d.IsDeleted);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在或无权限更新");
            }

            document.DocumentTitle = dto.DocumentTitle;
            document.UpdatedAt = DateTime.UtcNow;
            await _db.SaveChangesAsync();

            return ApiResult.Success("文档更新成功", new
            {
                document.DocumentId,
                document.DocumentTitle,
                document.DocumentFileName,
                document.DocumentStatus,
                document.UpdatedAt
            });
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"更新文档失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 更新文档状态
    /// </summary>
    public async Task<ApiResult> UpdateDocumentStatusAsync(Guid documentId, string status)
    {
        try
        {
            var document = await _db.Documents.FindAsync(documentId);
            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在");
            }

            document.DocumentStatus = status;
            document.UpdatedAt = DateTime.UtcNow;
            await _db.SaveChangesAsync();

            return ApiResult.Success("文档状态更新成功");
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"更新文档状态失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 搜索文档
    /// </summary>
    public async Task<ApiResult> SearchDocumentsAsync(SearchDocumentsDto dto)
    {
        try
        {
            var query = _db.Documents
                .Include(d => d.KnowledgeBase)
                .Where(d => d.UserId == dto.UserId && !d.IsDeleted);

            if (!string.IsNullOrEmpty(dto.Keyword))
            {
                query = query.Where(d => d.DocumentTitle.Contains(dto.Keyword) || 
                                       d.DocumentFileName.Contains(dto.Keyword));
            }

            if (dto.KnowledgeBaseId.HasValue)
            {
                query = query.Where(d => d.KnowledgeBaseId == dto.KnowledgeBaseId.Value);
            }

            if (!string.IsNullOrEmpty(dto.DocumentType))
            {
                query = query.Where(d => d.DocumentFileType == dto.DocumentType);
            }

            if (!string.IsNullOrEmpty(dto.Status))
            {
                query = query.Where(d => d.DocumentStatus == dto.Status);
            }

            var total = await query.CountAsync();
            var documents = await query
                .OrderBy(d => d.DocumentTitle).ThenBy(d => d.DocumentId) // 使用稳定的排序方式，避免启用禁用后上下跳动
                .Skip((dto.Page - 1) * dto.PageSize)
                .Take(dto.PageSize)
                .Select(d => new
                {
                    d.DocumentId,
                    d.DocumentTitle,
                    d.DocumentFileName,
                    d.DocumentFileType,
                    d.DocumentFileSize,
                    d.DocumentStatus,
                    d.DocumentAccessLevel,
                    d.CreatedAt,
                    KnowledgeBaseName = d.KnowledgeBase.KnowledgeBaseName
                })
                .ToListAsync();

            var result = new
            {
                Documents = documents,
                Total = total,
                Page = dto.Page,
                PageSize = dto.PageSize,
                TotalPages = (int)Math.Ceiling((double)total / dto.PageSize)
            };

            return ApiResult.Success("搜索文档成功", result);
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"搜索文档失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 批量上传文档
    /// </summary>
    public async Task<ApiResult> BatchUploadDocumentsAsync(BatchUploadDocumentsDto dto)
    {
        try
        {
            // 验证知识库是否存在（所有用户都可以访问所有知识库）
            var knowledgeBase = await _db.KnowledgeBases
                .FirstOrDefaultAsync(kb => kb.KnowledgeBaseId == dto.KnowledgeBaseId && kb.IsActive && !kb.IsDeleted);
            
            if (knowledgeBase == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "知识库不存在");
            }

            var uploadedDocuments = new List<object>();
            var failedDocuments = new List<object>();
            var documentsToAdd = new List<Document>();

            // 第一阶段：处理文件上传和创建实体（不保存到数据库）
            foreach (var file in dto.Files)
            {
                try
                {
                    // 生成文件路径
                    var fileName = $"{Guid.NewGuid()}_{file.FileName}";
                    var filePath = Path.Combine("uploads", "documents", fileName);
                    var fullPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", filePath);

                    // 确保目录存在
                    Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);

                    // 保存文件
                    using (var stream = new FileStream(fullPath, FileMode.Create))
                    {
                        await file.CopyToAsync(stream);
                    }

                    // 创建文档实体
                    var document = new Document
                    {
                        DocumentId = Guid.NewGuid(),
                        UserId = dto.UserId,
                        KnowledgeBaseId = dto.KnowledgeBaseId,
                        DocumentTitle = Path.GetFileNameWithoutExtension(file.FileName),
                        DocumentFileName = file.FileName,
                        DocumentFilePath = filePath,
                        DocumentFileType = Path.GetExtension(file.FileName).ToLower(),
                        DocumentFileSize = file.Length,
                        DocumentStatus = "uploaded",
                        DocumentAccessLevel = dto.DocumentAccessLevel,
                        CreatedAt = DateTime.UtcNow,
                        UpdatedAt = DateTime.UtcNow
                    };

                    documentsToAdd.Add(document);
                    uploadedDocuments.Add(new
                    {
                        document.DocumentId,
                        document.DocumentTitle,
                        document.DocumentFileName,
                        Status = "success"
                    });
                }
                catch (Exception ex)
                {
                    failedDocuments.Add(new
                    {
                        FileName = file.FileName,
                        Error = ex.Message,
                        Status = "failed"
                    });
                }
            }

            // 第二阶段：批量保存所有成功的文档到数据库
            if (documentsToAdd.Any())
            {
                _db.Documents.AddRange(documentsToAdd);
                await _db.SaveChangesAsync();

                // 第三阶段：异步处理文档（分块和向量化） - 使用新的作用域，避免请求作用域释放
                _ = Task.Run(async () =>
                {
                    foreach (var document in documentsToAdd)
                    {
                        try
                        {
                            using var scope = _scopeFactory.CreateScope();
                            var scopedRagService = scope.ServiceProvider.GetRequiredService<IAppRagService>();
                            await scopedRagService.ProcessDocumentAsync(document.DocumentId);
                        }
                        catch (Exception ex)
                        {
                            // 记录处理失败，但不影响上传结果
                            System.Diagnostics.Debug.WriteLine($"文档处理失败 {document.DocumentFileName}: {ex.Message}");
                        }
                    }
                });
            }

            var result = new
            {
                TotalFiles = dto.Files.Count,
                SuccessCount = uploadedDocuments.Count,
                FailedCount = failedDocuments.Count,
                UploadedDocuments = uploadedDocuments,
                FailedDocuments = failedDocuments
            };

            return ApiResult.Success("批量上传完成", result);
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"批量上传文档失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 更新文档权限
    /// </summary>
    public async Task<ApiResult> UpdateDocumentPermissionsAsync(UpdateDocumentPermissionsDto dto)
    {
        try
        {
            var document = await _db.Documents
                .FirstOrDefaultAsync(d => d.DocumentId == dto.DocumentId && d.UserId == dto.UserId);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在或无权限");
            }

            document.DocumentAccessLevel = dto.DocumentAccessLevel;
            document.UpdatedAt = DateTime.UtcNow;
            await _db.SaveChangesAsync();

            return ApiResult.Success("文档权限更新成功", new
            {
                document.DocumentId,
                document.DocumentTitle,
                document.DocumentAccessLevel
            });
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"更新文档权限失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 获取文档的文档块列表
    /// </summary>
    public async Task<ApiResult> GetDocumentChunksAsync(Guid documentId)
    {
        try
        {
            var document = await _db.Documents
                .Include(d => d.DocumentChunks)
                .FirstOrDefaultAsync(d => d.DocumentId == documentId && !d.IsDeleted);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在");
            }

            var chunks = await _db.DocumentChunks
                .Where(dc => dc.DocumentId == documentId)
                .OrderBy(dc => dc.ChunkIndex)
                .Select(dc => new
                {
                    dc.Id,
                    dc.ChunkIndex,
                    dc.DocumentChunkContent,
                    dc.TokenCount,
                    dc.CreatedAt,
                    HasVector = _db.Vectors.Any(v => v.DocumentChunkId == dc.Id)
                })
                .ToListAsync();

            var result = new
            {
                DocumentId = documentId,
                DocumentTitle = document.DocumentTitle,
                DocumentStatus = document.DocumentStatus,
                TotalChunks = chunks.Count,
                Chunks = chunks
            };

            return ApiResult.Success("获取文档块成功", result);
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"获取文档块失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 重新处理文档（重新分块和向量化）
    /// </summary>
    public async Task<ApiResult> ReprocessDocumentAsync(Guid documentId)
    {
        try
        {
            var document = await _db.Documents
                .FirstOrDefaultAsync(d => d.DocumentId == documentId && !d.IsDeleted);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在");
            }

            // 调用RAG服务重新处理文档
            var result = await _ragService.ProcessDocumentAsync(documentId);
            
            return result;
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"重新处理文档失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 下载文档
    /// </summary>
    public async Task<ApiResult> DownloadDocumentAsync(Guid documentId, Guid userId)
    {
        try
        {
            // 检查用户是否有查看所有文档的权限
            var canViewAll = await _permissionCheckService.CanViewAllAsync(userId, "document");
            
            var query = _db.Documents.AsQueryable();
            
            // 根据权限过滤数据
            if (!canViewAll)
            {
                query = query.Where(d => d.UserId == userId && !d.IsDeleted);
            }
            else
            {
                query = query.Where(d => !d.IsDeleted);
            }

            var document = await query
                .FirstOrDefaultAsync(d => d.DocumentId == documentId);

            if (document == null)
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档不存在或无权限访问");
            }

            // 构建完整的文件路径
            var fullPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", document.DocumentFilePath);

            if (!File.Exists(fullPath))
            {
                return ApiResult.Failed((int)ApiStatusCode.NOT_FOUND, "文档文件不存在");
            }

            // 获取文件信息
            var fileInfo = new FileInfo(fullPath);
            var contentType = GetContentType(document.DocumentFileType);

            var result = new DocumentDownloadInfoDto
            {
                FilePath = fullPath,
                FileName = document.DocumentFileName,
                ContentType = contentType,
                FileSize = fileInfo.Length,
                DocumentId = document.DocumentId,
                DocumentTitle = document.DocumentTitle
            };

            return ApiResult.Success("获取文档下载信息成功", result);
        }
        catch (Exception ex)
        {
            return ApiResult.Failed((int)ApiStatusCode.INTERNAL_ERROR, $"获取文档下载信息失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 当原始文件缺失时，根据文档分块内容动态生成文本文件用于下载
    /// </summary>
    public async Task<(byte[] bytes, string contentType, string fileName)?> GenerateTextFromChunksAsync(Guid documentId, Guid userId)
    {
        try
        {
            // 权限与可见性校验与下载一致
            var canViewAll = await _permissionCheckService.CanViewAllAsync(userId, "document");
            var query = _db.Documents.AsQueryable();
            if (!canViewAll)
            {
                query = query.Where(d => d.UserId == userId && !d.IsDeleted);
            }
            else
            {
                query = query.Where(d => !d.IsDeleted);
            }

            var document = await query.FirstOrDefaultAsync(d => d.DocumentId == documentId);
            if (document == null)
            {
                return null;
            }

            // 读取分块内容并拼接
            var chunks = await _db.DocumentChunks
                .Where(c => c.DocumentId == documentId)
                .OrderBy(c => c.ChunkIndex)
                .Select(c => c.DocumentChunkContent)
                .ToListAsync();

            if (chunks == null || chunks.Count == 0)
            {
                return null;
            }

            var builder = new StringBuilder();
            builder.AppendLine($"标题: {document.DocumentTitle}");
            builder.AppendLine();
            foreach (var chunk in chunks)
            {
                builder.AppendLine(chunk);
                builder.AppendLine();
            }

            var content = builder.ToString();
            var bytes = Encoding.UTF8.GetBytes(content);
            var fallbackFileName = Path.GetFileNameWithoutExtension(document.DocumentFileName);
            fallbackFileName = string.IsNullOrWhiteSpace(fallbackFileName) ? document.DocumentId.ToString() : fallbackFileName;
            fallbackFileName += "_from_chunks.txt";

            return (bytes, "text/plain; charset=utf-8", fallbackFileName);
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 根据文件扩展名获取Content-Type
    /// </summary>
    private string GetContentType(string fileExtension)
    {
        return fileExtension.ToLower() switch
        {
            ".pdf" => "application/pdf",
            ".doc" => "application/msword",
            ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            ".txt" => "text/plain",
            ".md" => "text/markdown",
            ".html" => "text/html",
            ".htm" => "text/html",
            ".json" => "application/json",
            ".xml" => "application/xml",
            ".csv" => "text/csv",
            ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            ".xls" => "application/vnd.ms-excel",
            ".ppt" => "application/vnd.ms-powerpoint",
            ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            _ => "application/octet-stream"
        };
    }
}
